package io.xiyou.order.service.impl;

import io.xiyou.account.api.IAccountInfoService;
import io.xiyou.core.lock.DLock;
import io.xiyou.order.api.IOrderService;
import io.xiyou.order.api.bo.AddOrderBO;
import io.xiyou.order.api.bo.PayOrderBO;
import io.xiyou.order.api.dto.OrderDTO;
import io.xiyou.order.dao.mapper.OrderMapper;
import io.xiyou.order.dao.model.Order;
import io.xiyou.order.service.support.HmilySupport;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.Reference;
import org.dromara.hmily.annotation.HmilyTCC;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.*;

/**
 * @author 西柚
 */
@Slf4j
@Component
@Transactional(rollbackFor = Exception.class)
public class OrderServiceImpl implements IOrderService {

    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private HmilySupport hmilySupport;

    @Reference
    private IAccountInfoService accountInfoService;

    /**
     * 创建订单
     *
     * @param addOrderBO
     */
    @Override
    public OrderDTO createOrder(AddOrderBO addOrderBO) {
        Order order = new Order();
        BeanUtils.copyProperties(addOrderBO, order);
        order.setOrderStatus(1);
        order.setCreateDate(new Date());
        order.setDelFlag(0);

        orderMapper.insert(order);

        OrderDTO orderDTO = new OrderDTO();
        BeanUtils.copyProperties(order, orderDTO);

        return orderDTO;
    }

    /**
     * 批量创建订单
     */
    @Override
    public void batchCreateOrder() {
        long time = System.currentTimeMillis();

        ExecutorService executorService = Executors.newFixedThreadPool(100);

        List<Future<String>> list = new ArrayList<Future<String>>();
        for (int i = 1; i <= 10; i++) {
            list.add(executorService.submit(new Callable<String>() {
                        public String call() throws Exception {
                            orderMapper.batchInsert(getOrderList());
                            return null;
                        }
                    })
            );

        }
        for (Future<String> future : list) {
            try {
                future.get(5, TimeUnit.SECONDS);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        executorService.shutdown();

        System.out.println("总耗时===" + (System.currentTimeMillis() - time) + "ms");
    }

    private List<Order> getOrderList() {
        List<Order> orderList = new ArrayList<>();
        for (int i = 0; i < 1000; i++) {
            orderList.add(getOrder());
        }
        return orderList;
    }

    private Order getOrder() {
        Order order = new Order();
        order.setUserId(888211438397689021L);
        order.setGoodsId(21312312312L);
        order.setOriginalPrice(new BigDecimal(100));
        order.setDiscountsPrice(new BigDecimal(10));
        order.setPayPrice(new BigDecimal(90));
        order.setReceiveName("李四");
        order.setReceivePhone("17777777778");
        order.setReceiveAddress("广东省广州市天河区XX路XX号");
        order.setPayType("wechat_app");
        order.setSource(1);
        order.setOrderStatus(1);
        order.setCreateBy("西柚");
        order.setCreateDate(new Date());
        order.setDelFlag(0);
        return order;
    }

    /**
     * 支付订单
     *
     * @param payOrderBO
     */
    @Override
    @Transactional
    @DLock("payOrderLock:" + "#{#payOrderBO.orderCode}")
    @HmilyTCC(confirmMethod = "commit", cancelMethod = "rollback")
    public void payOrder(PayOrderBO payOrderBO) {
        String xid = payOrderBO.getXid();
        try {
            Thread.sleep(10000);
        }catch (Exception e){

        }

        //获取全局事务id
        log.info("order try begin 开始执行...xid:{}", xid);
        //幂等判断 判断local_try_log表中是否有try日志记录，如果有则不再执行
        if (hmilySupport.isExistTry(xid) > 0) {
            log.info("order try 已经执行，无需重复执行,xid:{}", xid);
            return;
        }

        //try悬挂处理，如果cancel、confirm有一个已经执行了，try不再执行
        if (hmilySupport.isExistConfirm(xid) > 0 || hmilySupport.isExistCancel(xid) > 0) {
            log.info("order try悬挂处理  cancel或confirm已经执行，不允许执行try,xid:{}", xid);
            return;
        }

        Order order = orderMapper.selectById(payOrderBO.getOrderCode());
        if (Objects.isNull(order)) {
            throw new RuntimeException("order try 订单不存在");
        } else if (1 != order.getOrderStatus()) {
            throw new RuntimeException("order try 订单状态错误");
        }

        // 账户扣款
        accountInfoService.subtractAccountBalance(xid, order.getUserId(), order.getPayPrice());
    }

    /**
     * confirm方法
     *
     * @param payOrderBO
     */
    @Transactional(rollbackFor = Exception.class)
    public void commit(PayOrderBO payOrderBO) {
        Order updateOrder = new Order();
        updateOrder.setOrderCode(payOrderBO.getOrderCode());
        updateOrder.setPayType("balance");
        updateOrder.setOrderStatus(2);
        updateOrder.setPayDate(new Date());
        updateOrder.setUpdateBy(payOrderBO.getUpdateBy());
        updateOrder.setUpdateDate(new Date());

        // 支付成功、修改订单状态
        orderMapper.paySuccess(updateOrder);

        log.info("order confirm begin 开始执行...xid:{},orderCode:{}", payOrderBO.getXid(), payOrderBO.getOrderCode());
    }


    /**
     * cancel方法
     * cancel幂等校验
     * cancel空回滚处理
     *
     * @param payOrderBO
     */
    @Transactional(rollbackFor = Exception.class)
    public void rollback(PayOrderBO payOrderBO) {
        // 支付失败，无需操作

        log.info("order cancel end 结束执行...xid:{}", payOrderBO.getXid());
    }


    /**
     * 订单详情
     *
     * @param orderCode
     * @return
     */
    @Override
    @Cacheable(key = "#orderCode", value = "orderCache")
    public OrderDTO getOrderDetails(Long orderCode) {
        Order order = orderMapper.selectByOrderCode(orderCode);
        if (Objects.isNull(order)) {
            return null;
        }

        OrderDTO orderDTO = new OrderDTO();
        BeanUtils.copyProperties(order, orderDTO);

        return orderDTO;
    }

    /**
     * 根据用户ID查询订单列表
     *
     * @param userId
     * @return
     */
    @Override
    @Cacheable(key = "#userId", value = "userOrderCache", unless = "#result == null or #result.size() == 0")
//    @Cacheable //(key="methodName",value="userCache")
    public List<OrderDTO> getByUserId(Long userId) {
        List<Order> orderList = orderMapper.getByUserId(userId);

        List<OrderDTO> orderDTOList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(orderList)) {
            for (Order order : orderList) {
                OrderDTO orderDTO = new OrderDTO();
                BeanUtils.copyProperties(order, orderDTO);
                orderDTOList.add(orderDTO);
            }
        }
        return orderDTOList;
    }

}
